'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' RENUMBER.BAS
' James Deakins, April 2013
'
' Renumbers MMBasic programs in a similar way to the old RENUM.BAS program
' that was removed from the MMBasic library, and the old RENUM command
' that was removed from MMBasic.
' This is a control program that chains to other programs.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Don't initialise variable UpTo to 0.  Let it default to 0 at program start.
' Otherwise config.bas will continually be called, even though config.bas 
' will set UpTo to 1.  The chain command restarts this program from the top,
' not from where the call was made.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' There's a fair bit of code to work around a bug with DOS MMBasic 4.3a 
' - parameters are not passed when we RUN RENUM, and we 
' cannot pass parameters to other programs using the RUN or the CHAIN 
' command from within this program.
' if you want to use parameters in the DOS version you must use the implied
' Run format (ie, don't use RUN RENUM [params], just use RENUM [params].
'
' RENUM [InFile][.bas] [OutFile][.bas] [/!] [/F] [indent] [/P]
' where Infile and Outfile are the file to renumber and the output filename,
' /! means just DO IT! (use the same values as last time, including infile and outfile),
' OR provide infile and outfile values, AND
'    /F means call the FORMAT program, 
'    indent is the format indent (1,2,3,4,5,6 spaces, default 2), and
'    /P means to pause the display of the formatted listing.
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Do line numbers within your code (ie, not at the start of lines) have 
' asterisks in front of them?  
' eg. 10 if x = 1 then goto ***50
' If so, disable debug mode by editing the renumber.cfg file and changing bDebug
' from True to False, or use the /D parameter to toggle bDebug.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'

If UpTo = 0 then
  IF MM.VER < 4.0301 then
    PRINT
    PRINT "You are running version";MM.VER;" of MMBasic."
    PRINT "You need at least version 4.03a because it"
    PRINT "has the Chain command, which allows programs"
    PRINT "this large to be split into modules, and a"
    PRINT "required bugfix."
    PRINT
    END
  ENDIF

  Option Base 1 
  False = 0: True = NOT False 
 
  If MM.DEVICE$ = "Colour Maximite" then
    MODE 1                ' free up max memory on CMM, run in monochrome
  ENDIF      
    
  maxParams=20
  DIM Param$(MaxParams)   ' for the parameters after a keyword, and also for parsing command line 
  DIM ParamPtr(MaxParams) ' points to start of each parameter in the string after a keyword

  MasterFile$   = MM.FName$                                      ' this program name - so chained programs can return
  ConfFileName$ = Left$(MasterFile$,LEN(MasterFile$)-4) + ".cfg" ' same name as this file, but with .cfg extension

  ' work around bug. In DOS MMBasic 4.3a RUN RENUM returns null string for MM.CMDLINE$.  Prompt for values.

  ' parse the command line into separate parameters.  CMDs will hold the count of parameters.
  if MM.CMDLINE$ = "" then 
    CMDs = 0
  else
    CMDs = Parse(MM.CMDLINE$, 1)
  endif
  
  ' if there is one or more parameters
  '   if there's one parameter:
  '     check that it is only /!, /?, ?, /H[elp] OR /!
  '     if /!, set a flag to JUST DO IT
  '   if more than on parameter
  '     add .bas to input and output files if not already there
  '     set a flag if user wants to call FORMAT program
  '
  if CMDs > 0 then
    in$ = UCASE$(Param$(1))
    if in$ = "/?" OR in$ = "?" OR LEFT$(in$,2) = "/H" then
      PRINT "RENUM Help screen"
      PRINT "-----------------"
      PRINT "Can be run with no parameters - ie RENUM"
      PRINT "or RENUM /!"
      PRINT "or RENUM /? or ? or /H[ELP]"
      PRINT "or RENUM infile[.bas] outfile[.bas] [/F] [indent] [/P]"
      PRINT "where /! means just DO IT! (use the same values as last time),"
      PRINT "OR /? or ? or /H[ELP] which displays this help message,"
      PRINT "OR infile and outfile (with optional .bas extensions)"
      PRINT "        are the file to renumber and the output file,"
      PRINT "   AND [optional] /D means toggle debug mode (on to off, or off to on),"
      PRINT "   AND [optional] /F means call the FORMAT program," 
      PRINT "   AND [optional] indent is the format indent (1,2,3,4,5,6"
      PRINT "       default 2),"
      PRINT "   AND [optional] /P means to pause the display of the" 
      PRINT "       formatted listing." 
      END
    endif
                    
    bLastValues = (in$ = "/!")               ' flag to just use the last values stored in config file

    if NOT bLastValues then                  ' not Help, not just DO IT!, so normal parameters
      if CMDs = 1 then                       ' only one parameter - and it's not Help or just DO IT!
        PRINT "You must provide either NO Parameters at all (which will prompt you for them),"
        PRINT "one parameter (/? OR /H OR /!) OR"
        PRINT "an infile and outfile name, and optional extra parameters (/D, /F, indent, and /P)."
        PRINT "Please restart using the one of the valid sets of parameters."
        END
      endif
      
      ' if we get to here we have enough parameters to call RENUM43.BAS  . Note: Can't DIM(1).
      DIM CmdParamIn$(CMDs)                  ' save now because other programs use Param$ array.
      bCallFormat = FALSE
      bDebugToggle = FALSE
      FormatBasParameters$ = ""
      for n = 1 to CMDs
        in$ = Param$(n)
        if (n <= 2) then                     ' add .bas if no extension on first 2 parameters
          if INSTR(1, in$, ".") = 0 then
            in$ = in$ + ".bas"
          endif
        else ' n > 2
          in$ = UCASE$(in$) 
          if in$ = "/F" then
            bCallFormat = TRUE
          endif
          if in$ = "/D" then
            bDebugToggle = TRUE
          endif
          in$ = UCASE$(in$)
          if (in$ <> "/F") AND (in$ <> "/!") AND (in$ <> "/D") AND (Right$(in$,4)) <> ".BAS" then 
            FormatBasParameters$ = FormatBasParameters$ + in$ + " " ' yes, there's a trailing space, but not worth coding around 
          endif                
        endif
        CmdParamIn$(n) = in$                 ' save each of the parameters
      next n
    endif
  endif ' cmds > 0 (note: /! not processing except for setting the bLastValues flag)
 
  bReadConfig = TRUE         ' True => READ the config file
  Chain "config.bas"         ' read in parameters from config file

elseif UpTo = 1 then
  Chain "Renum43.bas"        ' Renumber the program
 
elseif UpTo = 2 then         ' set up for running FORMAT program, then run it (or chain to)
  if CMDs = 0 then           ' prompt for params if DOS bug still exists, or if none supplied 
    lastFormatBasParameters$ = ""     ' keep these separate so we can save them
    INPUT "Do you want to format the output (Y/N) "; in$
    in$ = UCASE$(in$)
    if in$ = "Y" then 
      bCallFormat = TRUE  
      COPY oname$ TO "FORMAT.TMP"       'oname$ was the output file for RENUM43. Copy it so it can be used as an input file
      CMDPARM$ = "FORMAT.TMP " + oname$ 'specify that FORMAT is to overwrite RENUM43's output file     
      
      ' now build our string of Format parameter
      INPUT "What indent do you want (1,2,3,4,5,6 Enter for default 2) "; in$
      in$ = UCASE$(in$)
      if in$ <> "" then
        lastFormatBasParameters$ = lastFormatBasParameters$ + in$ + " " 
      endif
      INPUT "Do you want to pause the display of Format's output (Y/N) "; in$
      in$ = UCASE$(in$)
      if in$ = "Y" then
        lastFormatBasParameters$ = lastFormatBasParameters$ + "/P"
      endif
      
      'and add the format parameters to the end of the CMD parameters.
      CMDPARM$ = CMDPARM$ + lastFormatBasParameters$
      PRINT "calling format program with parameters: "; CMDPARM$
      open "FORMAT.DAT" for output as #1
      PRINT #1, CMDPARM$
      CLOSE #1
      CHAIN "format.bas"      ' format.bas does not return to this program.
    endif
  else ' params passed in via command line.
    COPY oname$ TO "FORMAT.TMP"    ' an input file for the format program  
    ' Build CMDPARM$ so Format program can read params.
    CMDPARM$ = "FORMAT.TMP"                     ' input file
    CMDPARM$ = CMDPARM$ + " " + oname$          ' output file
    ' add everything except input and output filenames, /F and /! and /D to CMDPARM$
    if CMDs >= 2 then
      CMDPARM$ = CMDPARM$ + " " + FormatBasParameters$
    else ' only one parameter - /!, so check if we called format last time.  If so, use previous parameters.
      if lastbCallformat then
        CMDPARM$ = CMDPARM$ + " " + lastFormatBasParameters$
        bCallformat = TRUE
      endif
    endif    
    
    if bCallFormat then
      'if bDebug then PRINT #9, "calling format program with parameters: ";CMDPARM$
      open "FORMAT.DAT" for output as #1
      PRINT #1, CMDPARM$
      CLOSE #1
      CHAIN "format.bas"      ' format.bas does not return to this program.
    endif
    
  endif
  ' if we get to here the user had decided not to run FORMAT
  PRINT "No formatting performed."

elseif UpTo = 3 then         ' save the configuration details
  PRINT "Finished renumbering."
  bReadConfig = False        ' for this pass, WRITE the config file
  Chain "config.bas"

endif

END

'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Function Parse
' Parse the string into tokens based on spaces and commas
' as separators.  Store the tokens in the global Param$ array.
' Store the offset within the original line of the start of 
' each token into another global array, ParamPtr.
'
' Returns the number of parameters in the array
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function Parse(pStatement$, pPtr) 
    Local i, n, nextChar$, ParamNum, StatementLen
    
    ' Clear the array that will hold the parameters
    For i = 1 to MaxParams
      Param$(i) = ""
      ParamPtr(i) = 0
    Next i
    
    StatementLen = Len(pStatement$)
    
    ParamNum = 0  
    n = pPtr
    ' skip any leading spaces
    NextChar$ = mid$(pStatement$, n, 1)
    Do While NextChar$ = " "
      n = n + 1
      NextChar$ = mid$(pStatement$, n, 1)
    Loop
    
    ' At this point we have skipped all the spaces (if any) at the start of the line and are pointing at the first parameter
    
    Do While n <= StatementLen
      Parameter$ = ""
      ParamNum = ParamNum + 1
      ParamPtr(ParamNum) = n
      
      Do While (NextChar$ <> " ") AND (NextChar$ <> ",") AND (n <= StatementLen)
        Parameter$ = Parameter$ + NextChar$
        n = n + 1
        NextChar$ = mid$(pStatement$, n, 1)
      Loop
      
      Param$(ParamNum) = Parameter$
      
      Do While ((NextChar$ = " ") OR (NextChar$ = ",")) AND (n <= StatementLen)
        n = n + 1
        NextChar$ = mid$(pStatement$, n, 1)
      Loop
    Loop
    
    if bDebug then
      for i = 1 to ParamNum
        ? #9, "Param ";i; " is "; Param$(i)
      next i
    endif
    
    Parse = ParamNum
end Function   ' Parse
 
